//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Text;
using OpenLS.Core.Formatting;

namespace OpenLS.Core
{
    public class NumberFormat : Format
    {
        public NumberFormat(string code) : base(code)
        {
        }

        public override FormatCategory Category
        {
            get { return FormatCategory.Number; }
        }

        public override object GetFormattedValue(object o, IFormatValueConverter converter)
        {
            if (o == null)
                return "";
            if (o is string)
                return o;
            if (o is double)
            {
                Double d = (double) o;
                foreach (FormatClause e in Clauses)
                    if (e.Matches(d))
                        return e.Format(d);
                throw new NotSupportedException();
            }
            if (o is bool)
            {
                return BooleanToString((bool) o);
            }
            return o.ToString();
        }

        public override bool CanFormat(object o)
        {
            if (o is double)
                return true;

            return false;
        }

        internal override void Analyze(List<FormatToken> list)
        {
            List<List<FormatToken>> tokenClauses = new List<List<FormatToken>>();
            List<FormatToken> currentList = new List<FormatToken>();

            foreach (FormatToken token in list)
            {
                if (token is ClauseSeparatorToken)
                {
                    tokenClauses.Add(currentList);
                    currentList = new List<FormatToken>();
                }
                else
                    currentList.Add(token);
            }
            if (currentList.Count > 0)
                tokenClauses.Add(currentList);
            foreach (List<FormatToken> l in tokenClauses)
            {
                Clauses.Add(FormatClause.Create(this, l));
            }
            foreach (FormatClause clause in Clauses)
                clause.Adjust();
        }


        public virtual Format IncreaseDecimal()
        {
            FormatParser p = new FormatParser(Code);
            NumericToken lastNum = null;
            int lastNumIndex = -1;
            bool hasDot = false;
            for (int i = 0; i < p.Tokens.Count; i++)
            {
                FormatToken t = p.Tokens[i];
                if (t is DotToken)
                {
                    lastNum = null;
                    hasDot = true;
                }
                if (t is LiteralToken)
                {
                    LiteralToken literalToken = (LiteralToken) t;
                    if (literalToken.Code.StartsWith("E"))
                        break;
                }
                if (t is ClauseSeparatorToken)
                {
                    if (lastNum != null)
                    {
                        if (hasDot)
                            lastNum.IncreaseDecimal();
                        else
                        {
                            p.Tokens.Insert(lastNumIndex + 1, new NumericToken("0"));
                            p.Tokens.Insert(lastNumIndex + 1, new DotToken());
                        }
                    }
                    lastNum = null;
                    hasDot = false;
                }
                if (t is NumericToken)
                {
                    lastNum = (NumericToken) t;
                    lastNumIndex = i;
                }
            }
            if (lastNum != null)
            {
                if (hasDot)
                    lastNum.IncreaseDecimal();
                else
                {
                    p.Tokens.Insert(lastNumIndex + 1, new NumericToken("0"));
                    p.Tokens.Insert(lastNumIndex + 1, new DotToken());
                }
            }
            StringBuilder newCode = new StringBuilder();
            foreach (FormatToken t in p.Tokens)
                newCode.Append(t.Code);

            return Parse(newCode.ToString());
        }

        public virtual Format DecreaseDecimal()
        {
            if (Code.Length <= 1)
                return this;
            FormatParser p = new FormatParser(Code);
            StringBuilder newCode = new StringBuilder();
            for (int i = 0; i < p.Tokens.Count; i++)
            {
                FormatToken t = p.Tokens[i];
                if (t is DotToken)
                {
                    if (i < p.Tokens.Count)
                    {
                        FormatToken tt = p.Tokens[i + 1];
                        if (tt is NumericToken)
                        {
                            NumericToken nt = (NumericToken) tt;
                            if (nt.Value.Length > 1)
                                p.Tokens[i + 1] = new NumericToken(nt.Value.Substring(0, nt.Value.Length - 1));
                            else
                            {
                                p.Tokens.RemoveAt(i);
                                p.Tokens.RemoveAt(i);
                            }
                        }
                    }
                }
            }
            foreach (FormatToken t in p.Tokens)
            {
                newCode.Append(t.Code);
            }
            return Parse(newCode.ToString());
        }
    }
}